#pragma once

template <class T>
class LinkedList
{
    template<class T>
    struct ListNode
    {
        T data;
        ListNode<T> *next;

        ListNode( T Data, ListNode* Next ): data( Data ), next( Next ) {};
    };

private:
    ListNode<T> *mHead;
    ListNode<T> *mTail;
    ListNode<T> *mCurrent;

public:
    LinkedList( void );
    ~LinkedList( void );

    void Add( T pData );
    void Delete( T pData );

    bool HasNext( void );

    T GetNext( void );
};

template <class T>
LinkedList<T>::LinkedList( void )
{
    mHead = 0;
    mTail = 0;
    mCurrent = 0;
}

template <class T>
LinkedList<T>::~LinkedList( void )
{
    while( mHead->next != 0 )
    {
        ListNode<T> *next = mHead->next;

        delete mHead;

        mHead = next;
    }

    delete mTail;
}

template <class T>
void LinkedList<T>::Add( T pData )
{
    static int i = 0;

    if( mHead == 0 )
    {
        mHead = new ListNode<T>( pData, 0 );
        mTail = mHead;
        mCurrent = mHead;
    }
    else
    {
        ListNode<T> *node = new ListNode<T>( pData, 0 );
        mTail->next = node;
        mTail = mTail->next;
    }
}

template <class T>
void LinkedList<T>::Delete( T pData )
{
    if( mHead != 0 )
    {
        ListNode<T> *node = 0;

        if( mHead->data == pData )
        {
            node = mHead;

            mHead = mHead->next;

            delete node;

            if( mHead == 0 )
            {
                mTail = 0;
                mCurrent = 0;
            }
        }
        else
        {
            node = mHead;

            while( node->next != 0 && node->next->data != data )
            {
                node = node->next;
            }

            if( node->next != 0 )
            {
                node->next = node->next->next;
            }

            if( node->next == 0 )
            {
                mTail = node;
            }
        }
    }
}

template <class T>
bool LinkedList<T>::HasNext( void )
{
    return mCurrent != mTail;
}

template <class T>
T LinkedList<T>::GetNext( void )
{
    ListNode<T> *node = mCurrent;

    if( mCurrent != mTail )
    {
        mCurrent = mCurrent->next;
    }
    else
    {
        mCurrent = mHead;
    }

    return node->data;
}